package discov

import (
	"fmt"
	"sync"

	"gitee.com/ameise84/e3utils/str_conv"
	"github.com/pkg/errors"
)

const (
	EventCreate = iota
	EventModify
	EventDel
)

type Event struct {
	Kind  int
	Key   string
	Value string
}

type WatchHandler interface {
	OnWatch([]Event)
}

func Start(opts *Options) error {
	newDriver, ok := _driverMp[opts.kind]
	if !ok {
		return errors.New(fmt.Sprintf("not find svc_disco:%s", opts.kind))
	}
	_gService = newDriver()
	if err := _gService.start(opts); err != nil {
		return errors.WithMessage(err, "start svc_disco")
	}
	return nil
}

func Stop() {
	_gService.stop()
}

func RegisterServiceHashID(serviceName string, ids map[uint64]struct{}) (ok bool, err error) {
	name := getServiceHashName(serviceName)
	ok = false
	err = _gService.lockDo(getLockName(name), func() error {
		for id := range ids {
			_, r, errGet := _gService.get(getServiceHashNameWithID(serviceName, str_conv.ToString(id)))
			if errGet != nil || r != nil {
				return errGet
			}
		}
		for id := range ids {
			errPut := _gService.put(getServiceHashNameWithID(serviceName, str_conv.ToString(id)), "0")
			if errPut != nil {
				return errPut
			}
		}
		ok = true
		return nil
	})
	return ok, err
}

func UnregisterServiceHashID(serviceName string, ids map[uint64]struct{}) (err error) {
	name := getServiceHashName(serviceName)
	err = _gService.lockDo(getLockName(name), func() error {
		for id := range ids {
			_, err2 := _gService.del(getServiceHashNameWithID(serviceName, str_conv.ToString(id)))
			if err == nil {
				err = err2
			}
		}
		return err
	})
	return err
}

func Watch(cb WatchHandler, serviceName string, id int64) error {
	return _gService.watch(cb, getServiceInstName(serviceName, ""), id+1)
}

func RegisterService(serviceName string, sessionID string, js string) error {
	return _gService.put(getServiceInstName(serviceName, sessionID), js)
}

func UnregisterService(serviceName string, sessionID string) error {
	_, err := _gService.del(getServiceInstName(serviceName, sessionID))
	return err
}

func UpdateService(serviceName string, sessionID string, js string) error {
	return _gService.update(getServiceInstName(serviceName, sessionID), js)
}

func GetServices(serviceName string) (id int64, jsons []string, err error) {
	return _gService.get(getServiceInstName(serviceName, ""))
}

func GetLocker(key string) sync.Locker {
	return _gService.getLocker(key)
}
func LockDo(key string, f func() error) error {
	return _gService.lockDo(getLockName(key), f)
}
